#include "poller.h"
#include "channel.h"
#include "elassert.h"

using namespace el;

Poller::Poller()
{
	max_fd_ = -1;
	FD_ZERO(&read_fds_);
	FD_ZERO(&write_fds_);
	FD_ZERO(&exception_fds_);
}

Poller::~Poller()
{
}

bool Poller::poll(ChannelVec& activ_channels, bool& find_flag)
{
	timeval time;
	time.tv_sec = 0;
	time.tv_usec = 10000;

	fd_set read = read_fds_;
	fd_set write = write_fds_;
	fd_set exception = exception_fds_;
	int number = select((int)(max_fd_ + 1), &read, &write, &exception, &time);
	if (number < 0 && WSAEINTR != number)
	{
		return false;
	}
	else if (number == 0)
	{
		find_flag = false;
	}
	else
	{
		findActivChannels(activ_channels, read, write, exception, number);
		find_flag = true;
	}
	return true;
}

bool el::Poller::updateChannel(Channel * channel)
{
	FD fd = channel->fd();
	if (channel_map_.find(fd) == channel_map_.end())
	{
		if (isFullLoad())
		{
			return false;
		}
		channel_map_[fd] = channel;
	}
	if (channel->noneEvent())
	{
		clearFD(fd);
		return true;
	}

	if (channel->hasReadEvent())
	{
		FD_SET(fd, &read_fds_);
	}
	else
	{
		FD_CLR(fd, &read_fds_);
	}

	if (channel->hasWriteEvent())
	{
		FD_SET(fd, &write_fds_);
	}
	else
	{
		FD_CLR(fd, &write_fds_);
	}

	if (channel->hasExceptionEvent())
	{
		FD_SET(fd, &exception_fds_);
	}
	else
	{
		FD_CLR(fd, &exception_fds_);
	}
	if (fd > max_fd_)
	{
		max_fd_ = fd;
	}
	return true;
}

void el::Poller::removeChannel(Channel * channel)
{
	FD fd = channel->fd();
	assert(channel_map_.find(fd) != channel_map_.end());
	assert(channel->noneEvent());
	channel_map_.erase(fd);
}

size_t el::Poller::getLoad()
{
	return channel_map_.size();
}

bool el::Poller::isFullLoad()
{
	assert(channel_map_.size() <= FD_SETSIZE);
	return channel_map_.size() == FD_SETSIZE;
}

void el::Poller::findActivChannels(ChannelVec & activ_channels, fd_set & read, fd_set & write, fd_set & exception, int number)
{
	for (ChannelVecIt it = channel_map_.begin(); it != channel_map_.end(); ++it)
	{
		if (it->second->noneEvent())
		{
			continue;
		}
		int revent = Channel::NONE_EVENT;
		if (FD_ISSET(it->first, &read))
		{
			revent |= Channel::READ_EVENT;
			--number;
		}
		if (FD_ISSET(it->first, &write))
		{
			revent |= Channel::WRITE_EVENT;
			--number;
		}
		if (FD_ISSET(it->first, &exception))
		{
			revent |= Channel::EXCEPTION_EVENT;
			--number;
		}
		if (Channel::NONE_EVENT != revent)
		{
			it->second->setREvent(revent);
			activ_channels.push_back(it->second);
		}
		if (number <= 0)
		{
			break;
		}
	}
	assert(0 == number);
}

void el::Poller::clearFD(FD fd)
{
	FD_CLR(fd, &read_fds_);
	FD_CLR(fd, &write_fds_);
	FD_CLR(fd, &exception_fds_);
	if (fd != max_fd_)
	{
		return;
	}
	ChannelRIt it(channel_map_.lower_bound(fd - 1));
	while (it != channel_map_.rend())
	{
		if (!it->second->noneEvent())
		{
			max_fd_ = it->second->fd();
			return;
		}
		it++;
	}
	max_fd_ = -1;
}
